#include <zdb/zdb.h>
#include <stdio.h>
#include <string.h>

#include <assert.h>

#include<sys/time.h>
#include  "log.h"
#include "auth.h"

#include <zdb/Exception.h>


ConnectionPool_T pool;

int open_db(char* ip, int port, char* username, char* passwd, char* db_name) {

    char strConn[1024] = {'\0'};

    sprintf(strConn, "mysql://%s:%d/%s?user=%s&password=%s", ip, port, db_name, username, passwd);

    URL_T url = URL_new(strConn);
    pool = ConnectionPool_new(url);

    if (pool) {
        ConnectionPool_start(pool);
    } else {
        return -1;
    }
    return 0;


}

int find_session(char* username, char* session_id, char* nasip) {
    Connection_T con = ConnectionPool_getConnection(pool);
    char sql[2018] = {'\0'};
    sprintf(sql, "select nasipaddress from radacct where username='%s' and acctsessionid='%s' limit 1", username, session_id);
    ResultSet_T result = Connection_executeQuery(con, sql);
    DEBUG("find session SQL is '%s'", sql);

    while (ResultSet_next(result)) {
        const char* buf = ResultSet_getString(result, 1);
        if (buf) {
            strncpy(nasip, buf, strlen(buf));
            ConnectionPool_returnConnection(pool, con);
            return 0;
        }

    }
    ConnectionPool_returnConnection(pool, con);
    return -1;

}

 int update_acu(char* mac, const char* nasip, const char* pubkey) {
       Connection_T con = ConnectionPool_getConnection(pool);
    char sql[2018] = {'\0'};
    sprintf(sql, "update acu  set topic='%s', pubkey='%s'  WHERE mac='%s' limit 1", nasip, pubkey,mac);
    DEBUG("sql=%s\n",sql);
     Connection_executeQuery(con, sql);
     
 
    ConnectionPool_returnConnection(pool, con);
    return -1;
    
}

int login_dev(const char* mac, const char* nasip, const char* secret) {
    DEBUG("devid\t=\t%s\n\t\t\t\ttopic\t=\t%s", mac, nasip);
    Exception_T C;

    char *sql = "SELECT id from acu  WHERE mac='?' AND pw='?' ;";
    Connection_T con = ConnectionPool_getConnection(pool);
    PreparedStatement_T p = Connection_prepareStatement(con, sql);

    struct timeval tv;
    struct timezone tz;


    if ((!mac) || (!nasip) || (!secret)) {
        DEBUG("func(%s), input args error", __FUNCTION__);
        return -1;
    }


    gettimeofday(&tv, &tz);


    PreparedStatement_setString(p, 1, mac);
    PreparedStatement_setString(p, 2, secret);

  int id=0;
//ResultSet_T r ;
    TRY
    ResultSet_T r = PreparedStatement_executeQuery(p);
      
    while(ResultSet_next(r)){
         id = ResultSet_getIntByName(r, "id");
    
    }
    THROW(C, "C");
    CATCH(C)

    ConnectionPool_returnConnection(pool, con);

    return id;
    FINALLY

    ConnectionPool_returnConnection(pool, con);
    return -1;
    END_TRY;
    ConnectionPool_returnConnection(pool, con);

    return id;

}

int delete_finished_session() {
     
    Exception_T C;

    char *sql = "DELETE from radacct WHERE trim(acctstoptime) <> \"\" OR ((acctstarttime+acctsessiontime + 3600) < now());";
    Connection_T con = ConnectionPool_getConnection(pool);
    PreparedStatement_T p = Connection_prepareStatement(con, sql);

  


    TRY
    PreparedStatement_execute(p);
    THROW(C, "C");
    CATCH(C)

    ConnectionPool_returnConnection(pool, con);
    return 0;
    FINALLY

    ConnectionPool_returnConnection(pool, con);
    return -1;
    END_TRY;
    ConnectionPool_returnConnection(pool, con);
    return 0;

}



int regist_dev(const char* mac, const char* nasip, const char* secret,const char* pubkey) {
    DEBUG("mac\t=\t%s\n\t\t\t\ttopic\t=\t%s", mac, nasip);
    Exception_T C;

    char *sql = "INSERT INTO acu (mac,topic,pw,regtime,pubkey) VALUES (?,?,?,?,?);";
    Connection_T con = ConnectionPool_getConnection(pool);
    PreparedStatement_T p = Connection_prepareStatement(con, sql);

    struct timeval tv;
    struct timezone tz;


    if ((!mac) || (!nasip) || (!secret)) {
        DEBUG("func(%s), input args error", __FUNCTION__);
        return -1;
    }


    gettimeofday(&tv, &tz);


    PreparedStatement_setString(p, 1, mac);
    PreparedStatement_setString(p, 2, nasip);
    PreparedStatement_setString(p, 3, secret);
    PreparedStatement_setInt(p, 4, tv.tv_sec);
PreparedStatement_setString(p, 5, pubkey);

    TRY
    PreparedStatement_execute(p);
    THROW(C, "C");
    CATCH(C)

    ConnectionPool_returnConnection(pool, con);
    return 0;
    FINALLY

    ConnectionPool_returnConnection(pool, con);
    return -1;
    END_TRY;
    ConnectionPool_returnConnection(pool, con);
    return 0;

}